import Position from "./Position"

class Snake {
  // 定义一个表示食物的元素
  element: HTMLElement

  // 蛇身（包括头）
  body: HTMLCollection

  // 蛇头
  head: HTMLElement

  // 坐标位置
  headPosition: Position

  bodyPositions: Position[] = []

  // 面板格数
  readonly boardSize = 30
  // 元素大小
  readonly elementSize = 10

  direction: string = "" // 初始方向

  prevDirection: string = "" // 上次方向

  growthSpurts: number = 0 // 蛇是否在生长

  constructor() {
    this.element = document.getElementById("snake")!
    this.body = this.element.children
    this.head = this.body[0] as HTMLElement

    this.headPosition = new Position(0, 0)
    this.bodyPositions.push(this.headPosition)
  }

  setDirection(direction: string) {
    this.prevDirection = this.direction
    this.direction = direction
  }

  // 移动蛇
  move() {
    let { x, y } = this.headPosition

    switch (this.direction) {
      case "ArrowUp":
      case "Up":
        y--
        break
      case "ArrowDown":
      case "Down":
        y++
        break
      case "ArrowLeft":
      case "Left":
        x--
        break
      case "ArrowRight":
      case "Right":
        x++
        break

      default:
        break
    }

    const newPosition = new Position(x, y)

    if (!!this.bodyPositions[1] && this.bodyPositions[1].isEqual(newPosition)) {
      this.direction = this.prevDirection
      return
    }

    this.headPosition = newPosition
    this.bodyPositions.unshift(this.headPosition)
    if (this.growthSpurts > 0) {
      this.growthSpurts--
    } else {
      this.bodyPositions.pop() // 移除蛇尾
    }

    try {
      this.checkCollision()
    } catch (error) {
      throw error
    }

    this.render()
  }

  render() {
    for (let i = 0; i < this.body.length; i++) {
      const { x, y } = this.bodyPositions[i]
      const node = this.body[i] as HTMLElement
      node.style.left = `${x * this.elementSize}px`
      node.style.top = `${y * this.elementSize}px`
    }
  }

  // 检查蛇是否碰到自己或墙壁
  checkCollision(): boolean {
    const { x, y } = this.headPosition

    // 检查蛇头是否碰到墙壁
    if (x < 0 || x >= this.boardSize || y < 0 || y >= this.boardSize) {
      throw new Error("碰到墙壁了")
    }
    // 检查蛇头是否碰到自己
    for (let i = 1; i < this.body.length; i++) {
      if (this.headPosition.isEqual(this.bodyPositions[i])) {
        throw new Error("碰到自己了")
      }
    }
    return false
  }

  // 吃到食物，蛇变长
  grow() {
    this.element.insertAdjacentHTML("beforeend", "<div></div>")
    this.body = this.element.children
    this.growthSpurts++
  }
}

export default Snake
